#include "Lexical.h"
using namespace std;

// 1. 初始化关键字
map<string, string> keywordMap = {
    {"main", "MAINTK"},
    {"const", "CONSTTK"},
    {"int", "INTTK"},
    {"break", "BREAKTK"},
    {"continue", "CONTINUETK"},
    {"if", "IFTK"},
    {"else", "ELSETK"},
    {"while", "WHILETK"},
    {"getint", "GETINTTK"},
    {"printf", "PRINTFTK"},
    {"return", "RETURNTK"},
    // 逻辑运算符
    {"!", "NOT"},
    {"&&", "AND"},
    {"||", "OR"},
    // 算术运算符
    {"+", "PLUS"},
    {"-", "MINU"},
    {"*", "MULT"},
    {"/", "DIV"},
    {"%", "MOD"},
    // 比较运算符
    {"<", "LSS"},
    {"<=", "LEQ"},
    {">", "GRE"},
    {">=", "GEQ"},
    {"==", "EQL"},
    {"!=", "NEQ"},
    // 赋值运算符
    {"=", "ASSIGN"},
    // 界符
    {";", "SEMICN"},
    {",", "COMMA"},
    {"(", "LPARENT"},
    {")", "RPARENT"},
    {"[", "LBRACK"},
    {"]", "RBRACK"},
    {"{", "LBRACE"},
    {"}", "RBRACE"},
    // 字符串
    {"\"", "STRCON"},
    // 数字常量
    {"INTCON", "INTCON"},
    // 字符常量
    {"void", "VOIDTK"}};

// 3. 判断单词类别
bool lexical::isNumber(char c)
{
    return (c >= '0' && c <= '9');
}

bool lexical::isUnder(char c)
{
    return (c == '_');
}

bool lexical::isLetter(char c)
{
    return ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'));
}

bool lexical::isDoubleSymbol(char c)
{
    return (c == '<' || c == '>' || c == '=' || c == '!' || c == '&' || c == '|');
}

bool lexical::isSimpleSymbol(char c)
{
    return (c == '+' || c == '-' || c == '*' || c == '/' || c == '%' || c == ';' || c == ',' || c == '(' || c == ')' || c == '[' || c == ']' || c == '{' || c == '}');
}

bool lexical::isStr(char c)
{
    return (c == '"');
}

string lexical::judgeKind(const string &str)
{
    if (keywordMap.count(str))
    {
        return keywordMap[str];
    }
    else
    {
        return "IDENFR";
    }
}

// 4. 分词
vector<pair<string, string>> lexical::wordDivision(string input)
{
    vector<pair<string, string>> result;
    int n = input.length();
    for (int i = 0; i < n; i++)
    {
        string temp;
        string temp2;

        if (input[i] == '/')
        {
            if (input[i + 1] == '/')
            { // 单行注释
                while (i < input.length() && input[i] != '\n')
                    i++;
            }
            else if (input[i + 1] == '*')
            {           // 多行注释
                i += 2; // skip "/*"
                while (i < input.length() - 1)
                { // ensure we have enough characters for "*/"
                    if (input[i] == '*' && input[i + 1] == '/')
                    {
                        i += 2; // skip "*/"
                        break;
                    }
                    i++;
                }
            }
        }

        if (isSimpleSymbol(input[i]))
        { // 判断是否为单一运算符
            temp = input[i];
            temp2 = temp;
        }

        if (isDoubleSymbol(input[i]))
        { // 判断是否可为双个运算符
            temp += input[i];
            if (isDoubleSymbol(input[i + 1]))
            {
                temp += input[i + 1];
                i++;
            }
            temp2 = temp;
        }

        if (isStr(input[i]))
        { // 判断是否为字符串 (STRCON)
            temp2 += input[i];
            i++;
            while (!isStr(input[i]))
            {
                temp2 += input[i];
                i++;
            }
            temp2 += input[i];
            temp = "\"";
        }

        if (isNumber(input[i]))
        { // 判断是否为数字常量 (INTCON)
            temp = "INTCON";
            temp2 += input[i];
            i++;
            while (isNumber(input[i]))
            {
                temp2 += input[i];
                i++;
            }
            i--;
        }

        if (isLetter(input[i]) || isUnder(input[i]))
        { // 判断是否为字母或下划线 (IDENFR)
            temp += input[i];
            i++;
            while (isLetter(input[i]) || isNumber(input[i]) || isUnder(input[i]))
            {
                temp += input[i];
                i++;
            }
            i--;
            temp2 = temp;
        }

        if (!temp.empty())
        {
            result.push_back(make_pair(judgeKind(temp), temp2));
        }
    }
    return result;
}